package field

import (
	"bytes"

	"gitee.com/yanwc/net/utils"
	gerrors "github.com/panjf2000/gnet/pkg/errors"
)

type (
	TLVType [1]byte
	TLVLen  [1]byte
)

func (l TLVLen) Uint8() uint8 {
	return utils.BytesToNumber[uint8](l[:])
}

// TLV 扩展字段
type TLV struct {
	TlvType  TLVType
	TlvLen   TLVLen
	TlvValue []byte
}

// TLVS 值集合
type TLVS struct {
	Data    map[uint8]TLV
	RawData []byte
}

type (
	KickStandType uint8  // 0:磁感应脚撑  1:RFID脚撑  2:磁感应+RFID脚撑
	MagneticState uint8  // 磁传感状态(KickStandType =1时忽略) true 在位，false不在位
	RFIDState     uint8  // RFID状态( KickStandType=0时忽略)
	RFIDLabel     string // 标签信息(KickStandType=0时忽略)

	AngleValue           [6]byte // 三轴角度值, 单位:0.1°
	HeadingAngleValue    [2]byte // 相对地理北朝向，单位:0.1°
	KickStandValue       [8]byte //
	TBeaconRealRssiValue [1]byte
)

const (
	KickStandTypeMagnetic        KickStandType = 0 // 磁感应脚撑
	KickStandTypeRFID            KickStandType = 1 // RFID脚撑
	KickStandTypeMagneticAndRFID KickStandType = 2 // 磁感应+RFID脚撑
)

const (
	OnSlot    MagneticState = 1 // 在位
	NotInSlot MagneticState = 0 // 不在位
)

const (
	RFIDStateNone       RFIDState = 0 // 0:标签未检测到
	RFIDStateNormal     RFIDState = 1 // 1:标签读取正常
	RFIDStateDisconnect RFIDState = 2 // 2:读卡器未连接
)

const (
	RFIDLabelDisconnect RFIDLabel = "-1"   // "-1": 读卡器模块未连接
	RFIDLabelFault      RFIDLabel = "-2"   // "-2": 读卡器模块故障
	RFIDLabelError      RFIDLabel = "-100" //"-100": 其他错误
)

// 支持值类型
const (
	angleType           = 0x00
	headingAngleType    = 0x09
	kickStandStateType  = 0x0C
	tBeaconRealRssiType = 0x0D
	kickStandType       = 0x14
)

// 值类型集合
var tlvTypes = []byte{
	angleType,
	headingAngleType,
	kickStandStateType,
	tBeaconRealRssiType,
	kickStandType,
}

type TLVSRaw []byte

func (tb TLVSRaw) TLVS() *TLVS {
	tlv := new(TLVS)
	tlv.Data = make(map[uint8]TLV)
	tlv.RawData = tb
	startIndex := 0
	endIndex := 0
	for _, v := range tlvTypes {
		startIndex = bytes.IndexByte(tb, v)
		if startIndex < 0 {
			continue
		}

		var tlvType TLVType
		var tlvLen TLVLen
		endIndex = startIndex + 1
		utils.LoadPacket(tb[startIndex:endIndex], tlvType[:])
		startIndex = endIndex
		endIndex = startIndex + 1
		utils.LoadPacket(tb[startIndex:endIndex], tlvLen[:])
		l := tlvLen.Uint8()
		tlvValue := make([]byte, l)
		if l > 0 {
			startIndex = endIndex
			endIndex = startIndex + int(l)
			utils.LoadPacket(tb[startIndex:endIndex], tlvValue[:])
		}
		tlv.Data[v] = TLV{
			TlvType:  tlvType,
			TlvLen:   tlvLen,
			TlvValue: tlvValue,
		}
	}

	return tlv
}

// pitch,roll,yaw三轴角度值, 单位:0.1°
func (ts *TLVS) Angle() (pitch int16, roll int16, yaw int16, err error) {
	tlvType := uint8(angleType)
	if v, ok := ts.Data[tlvType]; ok {
		if len(v.TlvValue) != len(AngleValue{}) || len(AngleValue{}) != int(v.TlvLen.Uint8()) {
			err = gerrors.ErrIncompletePacket
			return
		}

		pitch = utils.BytesToNumber[int16](v.TlvValue[0:2])
		roll = utils.BytesToNumber[int16](v.TlvValue[2:4])
		yaw = utils.BytesToNumber[int16](v.TlvValue[4:6])
	}

	return
}

// 相对地理北朝向，单位:0.1° 正值为有效的方向数据 负值为未获取到有效方向数据
func (ts *TLVS) HeadingAngle() (angle int16, err error) {
	tlvType := uint8(headingAngleType)
	if v, ok := ts.Data[tlvType]; ok {
		if int(v.TlvLen.Uint8()) != len(HeadingAngleValue{}) || len(HeadingAngleValue{}) != len(v.TlvValue) {
			err = gerrors.ErrIncompletePacket
			return
		}

		angle = utils.BytesToNumber[int16](v.TlvValue[:])
	}

	return
}

// 脚撑状态
// 脚撑状态
// byte[0]:脚撑类型:
// * 0:磁感应脚撑
// * 1:RFID脚撑
// * 2:磁感应+RFID脚撑
// byte[1]:磁传感状态(byte[0]=1时忽略)
// * 0:不在位
// * 1:在位
// byte[2]:RFID状态(byte[0]=0时忽略)
// * 0:标签未检测到
// * 1:标签读取正常
// * 2:读卡器未连接
// byte[N-3]: RFID标签信息(byte[0]=0时忽略)
// * "00000000": 有读卡器信息，但未扫描到标签
// * "XXXXXXXX": 正常读取到卡片ID信息
// * "-1": 读卡器模块未连接
// * "-2": 读卡器模块故障
// * "-100": 其他错误
func (ts *TLVS) KickStandState() (
	kickStandType KickStandType,
	magneticState MagneticState,
	rfidState RFIDState,
	rfidLabel RFIDLabel, err error,
) {
	tlvType := uint8(kickStandStateType)
	if v, ok := ts.Data[tlvType]; ok {
		if v.TlvLen.Uint8() == 0 || len(v.TlvValue) < 3 {
			err = gerrors.ErrIncompletePacket
			return
		}

		kickStandType = KickStandType(utils.BytesToNumber[uint8](v.TlvValue[0:1]))
		magneticState = MagneticState(utils.BytesToNumber[uint8](v.TlvValue[1:2]))
		rfidState = RFIDState(utils.BytesToNumber[uint8](v.TlvValue[2:3]))
		rfidLabel = RFIDLabel(utils.BytesToString(v.TlvValue[3:], false))
	}

	return
}

// 最强的蓝牙道钉信号强度(isTBeaconEnable = 1时上报)
func (ts *TLVS) TBeaconRealRssi() (v uint8, err error) {
	tlvType := uint8(tBeaconRealRssiType)
	if val, ok := ts.Data[tlvType]; ok {
		if int(val.TlvLen.Uint8()) != len(TBeaconRealRssiValue{}) || len(val.TlvValue) != len(TBeaconRealRssiValue{}) {
			err = gerrors.ErrIncompletePacket
			return
		}

		v = utils.BytesToNumber[uint8](val.TlvValue[:])
	}

	return
}

// 宏博脚撑信息 kickStandModel 脚撑型号 parkNo 站点编号 bikeNo 车位编号
// uint32:脚撑型号:
// uint16:站点编号:
// uint16:车位编号:
func (ts *TLVS) KickStand() (kickStandModel uint32, parkNo uint16, bikeNo uint16, err error) {
	tlvType := uint8(kickStandType)
	if v, ok := ts.Data[tlvType]; ok {
		if int(v.TlvLen.Uint8()) != len(KickStandValue{}) || len(v.TlvValue) != len(KickStandValue{}) {
			err = gerrors.ErrIncompletePacket
			return
		}

		kickStandModel = utils.BytesToNumber[uint32](v.TlvValue[0:4])
		parkNo = utils.BytesToNumber[uint16](v.TlvValue[4:6])
		bikeNo = utils.BytesToNumber[uint16](v.TlvValue[6:8])
	}

	return
}
